/** file InstrumentFactory.cpp
    author belot.nicolas
*/

#include "InstrumentFactory.h"
#include "InstrumentMonophonique.h"
#include "InstrumentPolyphonique.h"
#include "InstrumentMultiphonique.h"
#include "InstrumentPerc.h"
#include <iostream>
#include <fstream>
#include <sstream>

namespace libtrckr {
using namespace std;
template<typename T>
bool from_string( const std::string & Str, T & Dest )
{
    // créer un flux à partir de la chaîne donnée
    std::istringstream iss( Str );
    // tenter la conversion vers Dest
    return iss >> Dest != 0;
}

string& trim(string &str){
	int first = str.find_first_not_of(" \t");
	int last = str.find_last_not_of(" \t");
	if(first == last){
		int sp = str.find_first_of(" \t");
		if(sp > first){
			str=str.substr(0,sp);
		}else{
			str = str.substr(first);
		}
		//start or end did not have sapce
	}else{
		str=str.substr(first, last-first);
	}
	return str;
}

void InstrumentFactory::setGlobals(string* item, string* value, global* data){
	if(item->find("name")!=string::npos){
		data->name=new string( trim(*value));
	}else if(item->find("type") != string::npos){
		data->type = new string(trim(*value));
	}else if(item->find("tuning")!=string::npos){
		data->tuning = new string(trim(*value));
	}else if(item->find("directory")!=string::npos){
		data->directory = new string(trim(*value));
	}else{
		cerr << "unknow item " << *item << endl;
	}
}

void InstrumentFactory::setAttack(string* item, string* value, attak* data){
	if(item->find("name")!=string::npos){
		data->name=new string( trim(*value));
	}else{
		cerr << "unknow item " << *item << endl;
	}
}

void InstrumentFactory::setSample(string* item, string* value, asample* data){
	if(item->find("note")!=string::npos){
		data->note=new string( trim(*value));
	}else if(item->find("file")!=string::npos){
		data->file = new string(trim(*value));
	}else if(item->find("speed")!=string::npos){
		std::cout << "speed" << *value << ":" << trim(*value) << std::endl;
		from_string(trim(*value), data->speed);
		std::cout << data->speed << std::endl;
		//data->speed = Double::tofloat(*value);
	}else if(item->find("panning")!=string::npos){
		from_string(trim(*value),data->panning);
	}else {
		cerr << "unknow item " << *item << endl;
	}
}
DynArray<string> splitString(string data, char delim){
	int cnt=0;
	int pos=data.find_first_not_of(delim);
	while( (pos = data.find_first_of(delim, pos)) != string::npos){
		cout << pos << endl;
		cnt++;pos++;
	}
	cnt++;
	DynArray<string> ret;
	if(cnt==1){
		ret = DynArray<string>(1,data);
	}else{
		ret = DynArray<string>(cnt,string());
		pos=0;
		int prev=0;
		for(uint i=0;i<cnt;i++){
			prev=pos;
			pos = data.find_first_of(delim,pos);
			ret[i]=data.substr(prev,pos-prev);
		}
	}
	return ret;
}
Instrument* InstrumentFactory::CreateInstrumentFromFile(string name) {
	char b[1024];
	global data;
	string entry;
	size_t pos;
	int cnt_att=0;
	fstream instr(name.c_str(),fstream::in);
	context_t context=GLOBAL;
	while(!instr.eof()){
		instr.getline(b,1024);
		entry= string(b,instr.gcount());
		pos = entry.find_first_of("=");
		if(pos!=string::npos){
			string* item = new string(entry, 0,pos);
			string * value= new string(entry,pos+1);
			if(context ==GLOBAL){
				setGlobals(item, value, &data);
			}else if(context == ATTACK){
				setAttack(item,value, data.attack[cnt_att-1]);
			}else if(context == SAMPLE){
				setSample(item,value, data.attack[cnt_att-1]->samples[data.attack[cnt_att-1]->cnt_smp-1]);
			}
			delete item;
			delete value;
		}else{//context switch.
			pos = entry.find_first_of("{");
			if(pos!=string::npos){
				if(entry.find("attack")!=string::npos){
					context=ATTACK;
					if(cnt_att==0){
						cnt_att++;
						data.attack = (attak**) malloc(sizeof(attak*)*cnt_att);
						data.attack[cnt_att-1] = (attak*)malloc(sizeof(attak));
						data.attack[cnt_att-1]->cnt_smp=0;
					}else{
						cnt_att++;
						data.attack = (attak**) realloc(data.attack,sizeof(attak*)*cnt_att);
						data.attack[cnt_att-1] = (attak*)malloc(sizeof(attak));
						data.attack[cnt_att-1]->cnt_smp=0;
					
					}
				}
				if(entry.find("sample")!=string::npos){
					context=SAMPLE;
					if(data.attack[cnt_att-1]->cnt_smp == 0){
						data.attack[cnt_att-1]->cnt_smp++;
						data.attack[cnt_att-1]->samples = (asample**)malloc(sizeof(asample*)*(data.attack[cnt_att-1]->cnt_smp ));
						data.attack[cnt_att-1]->samples[data.attack[cnt_att-1]->cnt_smp-1] = (asample*)malloc(sizeof(asample));
					}else{
						data.attack[cnt_att-1]->cnt_smp++;
						data.attack[cnt_att-1]->samples = (asample**)realloc(data.attack[cnt_att-1]->samples,sizeof(asample*)*(data.attack[cnt_att-1]->cnt_smp ));
						data.attack[cnt_att-1]->samples[data.attack[cnt_att-1]->cnt_smp-1] = (asample*)malloc(sizeof(asample));
						data.attack[cnt_att-1]->samples[data.attack[cnt_att-1]->cnt_smp-1]->panning=50;
					}
				}
				

			}else{
				pos = entry.find_first_of("}");
				if(pos!=string::npos){
					if(context==SAMPLE){
						context=ATTACK;
					}else if(context==ATTACK){
						context=GLOBAL;
					}else{
						cerr << "Unknown context " << endl;
					}
				}
			}
		}
	}
	Instrument *is;
	if(data.type->find("InstrumentMonophonique")!=string::npos){
		is = new InstrumentMonophonique();
	}else if(data.type->find("InstrumentMultiphonique")!=string::npos){
		is = new InstrumentMultiphonique();
	}else if(data.type->find("InstrumentPolyphonique")!=string::npos){
		is = new InstrumentPolyphonique();
	}else if(data.type->find("InstrumentPerc")!=string::npos){
		is = new InstrumentPerc();
	}else{
		cerr << "unknown instrument type ( " << *(data.type) <<" )" <<endl;
		exit(0);
	}
	is->setName(*(data.name));
	DynArray<string> mattack(cnt_att,string());
	for(uint i=0;i<cnt_att;i++){
		mattack[i]=string(*(data.attack[i]->name));
	}
	is->setAttack(mattack);
	mattack=splitString(*(data.tuning), ' ');
	is->setTuning(mattack);
	cout << "Name " << *(data.name) << endl << "Type " << *(data.type) << endl << "Tuning " << *(data.tuning) << endl << "Directory " << *(data.directory) << endl;
	for(uint i=0;i<cnt_att;i++){
	cout << "Attack " << *(data.attack[i]->name) << endl;
	cout << "Nombre de sample " << (data.attack[i]->cnt_smp) << endl;
		for(uint j=0;j<(data.attack[i]->cnt_smp);j++){
			is->setNote(*(data.attack[i]->samples[j]->note),*(data.directory) + "/" + *(data.attack[i]->samples[j]->file),1.0,0,i,0);
			cout << "Note " << *(data.attack[i]->samples[j]->note) << endl;
			cout  << "File " << *(data.directory) << "/" << *(data.attack[i]->samples[j]->file) << endl;
			cout  << "Vitesse " << data.attack[i]->samples[j]->speed << endl;
		}
	}
	//freeing allocated data.
	for(uint i=0;i<cnt_att;i++){
		for(uint j=0;j< data.attack[i]->cnt_smp;j++){
			delete data.attack[i]->samples[j]->note;
			delete data.attack[i]->samples[j]->file;
			free(data.attack[i]->samples[j]);
		}
		free(data.attack[i]->samples);
		delete data.attack[i]->name;
		free(data.attack[i]);
	}
	free(data.attack);
	delete data.name;
	delete data.type;
	delete data.tuning;
	delete data.directory;
	return is;

}

Instrument* InstrumentFactory::CreateInstrumentFromType(string type){}

}

